package com.airy.highSpeed.task;

import com.airy.highSpeed.controller.*;
import com.airy.highSpeed.entity.*;
import com.airy.highSpeed.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author: Ding Ya Kun.
 * @Description:
 * @Date:Created in 2020.12.18 17:12
 */
@Component

@RestController
@RequestMapping("product/task")
public class FixedPrintTask {

    @Autowired
    StaLaneHeartBeatController staLaneHeartBeatController;

    @Autowired
    StationparentController stationparentController;

    @Autowired
    TrHourFlowController trHourFlowController;

    @Autowired
    ExpresswayInfController expresswayInfController;

    @Autowired
    CktxCpcController cktxCpcController;

    @Autowired
    CktxEtcController cktxEtcController;

    @Autowired
    FlowTrafficController flowTrafficController;

    //车道ETC、MTC、混合ETC/MTC计算
    //每10min计算一次0
    @Scheduled(cron = "0 */10 * * * ?")
//    @RequestMapping("/456")
    public void express() {
        //从expressway_inf表得到ExpresswayInfEntity对象的集合
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "执行了");
        List<ExpresswayInfEntity> expresswayInfEntityList = expresswayInfController.findAll();

        if (expresswayInfEntityList.size() > 0) {
            //遍历集合
            for (ExpresswayInfEntity expresswayInfEntity : expresswayInfEntityList) {
                //根据ExpresswayInfEntity对象的TollStationId属性得到staLaneHeartBeatEntity对象的list集合
                List<StaLaneHeartBeatEntity> staLaneHeartBeatEntitys = staLaneHeartBeatController.findByTollStationId(expresswayInfEntity.getTollStationId());
                //入口ETC实际开启数
                int enETC = 0;
                //入口ETC总数
                int totalenETC = 0;
                //入口MTC实际开启数
                int enMTC = 0;
                //入口MTC总数5
                int totalenMTC = 0;
                //入口混合车道实际开启数
                int enHH = 0;
                //入口混合车道总数
                int totalenHH = 0;
                //出口ETC实际开启数
                int exETC = 0;
                //出口ETC总数
                int totalexETC = 0;
                //出口MTC实际开启数
                int exMTC = 0;
                //出口MTC总数
                int totalexMTC = 0;
                //出口混合车道实际开启数
                int exHH = 0;
                //出口混合车道总数
                int totalexHH = 0;
                if (staLaneHeartBeatEntitys.size() > 0) {
                    //遍历集合
                    for (StaLaneHeartBeatEntity staLaneHeartBeatEntity : staLaneHeartBeatEntitys) {

                        //车道类型 ,1-ETC,2-MTC,3-混合
                        int laneType = Integer.parseInt(staLaneHeartBeatEntity.getLaneType());
                        //出入口标识，1-入口，2-出口
                        int laneSign = Integer.parseInt(staLaneHeartBeatEntity.getLaneSign());
                        //车道状态，0-开启车道，1-关闭车道
                        int laneStatus = Integer.parseInt(staLaneHeartBeatEntity.getLaneStatus());

                        if (laneSign == 1 && laneType == 1) {
                            //入口ETC总数
                            totalenETC++;
                            if (laneStatus == 0) {
                                //入口ETC实际开启数
                                enETC++;
                            }
                        }
                        if (laneSign == 1 && laneType == 2) {
                            //入口MTC总数
                            totalenMTC++;
                            if (laneStatus == 0) {
                                //入口MTC实际开启数
                                enMTC++;
                            }
                        }
                        if (laneSign == 1 && laneType == 3) {
                            //入口混合总数
                            totalenHH++;

                            if (laneStatus == 0) {
                                //入口混合实际开启数
                                enHH++;
                            }
                        }
                        if (laneSign == 2 && laneType == 1) {
                            //出口ETC总数
                            totalexETC++;
                            if (laneStatus == 0) {
                                //出口ETC实际开启数
                                exETC++;
                            }
                        }
                        if (laneSign == 2 && laneType == 2) {

                            //出口MTC总数
                            totalexMTC++;
                            if (laneStatus == 0) {
                                //出口MTC实际开启数
                                exMTC++;
                            }
                        }
                        if (laneSign == 2 && laneType == 3) {
                            //出口混合总数
                            totalexHH++;
                            if (laneStatus == 0) {
                                //出口混合实际开启数
                                exHH++;
                            }
                        }
                        //将对应属性的值保存到对象中
                        expresswayInfEntity.setEntranceETC(String.valueOf(enETC));
                        expresswayInfEntity.setTotalEntranceETC(String.valueOf(totalenETC));
                        expresswayInfEntity.setEntranceMTC(String.valueOf(enMTC));
                        expresswayInfEntity.setTotalEntranceMTC(String.valueOf(totalenMTC));
                        expresswayInfEntity.setEntranceHH(String.valueOf(enHH));
                        expresswayInfEntity.setTotalEntranceHH(String.valueOf(totalenHH));
                        expresswayInfEntity.setExitETC(String.valueOf(exETC));
                        expresswayInfEntity.setTotalExitETC(String.valueOf(totalexETC));
                        expresswayInfEntity.setExitMTC(String.valueOf(exMTC));
                        expresswayInfEntity.setTotalExitMTC(String.valueOf(totalexMTC));
                        expresswayInfEntity.setExitHH(String.valueOf(exHH));
                        expresswayInfEntity.setTotalExitHH(String.valueOf(totalexHH));
                        expresswayInfEntity.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    }
                }
                //向expressway_inf表中更新数据
                expresswayInfController.updateByTollStationId(expresswayInfEntity);
                System.out.println(expresswayInfEntity.getStationName() + "更新成功");
            }
        }
    }

    //每周一零点执行一次，预测本周各收费站每小时的流量
    //从expresswayInf表查询收费站编号和收费站名称
    //然后根据条件从FLOWTRAFFIC表中查询数据进行预测该收费站本周每小时的数据
    //然后查询数据，将真实数据进行更新替换预测的数据
    //目前113个收费站，一个收费站一小时两条，出口和入口，一天24小时，一周七天，每周一零点三十分钟执行一次
    //113 X 2 X 24 X 7 = 37968 条数据
    @Scheduled(cron = "0 30 0 ? * MON")
//    @RequestMapping("/123")
    public void forecast() {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + ",星期 " + DateUtil.getWeek(new Date()) + " 执行了");
        //先去mysql的expresswayInf表中查询出天津所有的收费站(StationName)以及收费站编号(TollStationId)
        List<String> tollStationIdList = expresswayInfController.findTollStationIdNotNull();

        Date date = new Date();//当前时间
        Date lllMonday = geLastWeekMonday(geLastWeekMonday(geLastWeekMonday(date)));//上上上周周一
        Date lllSunday = geLastWeekSunday(geLastWeekSunday(geLastWeekSunday(date)));//上上上周周日
        Date llMonday = geLastWeekMonday(geLastWeekMonday(date));//上上周周一
        Date llSunday = geLastWeekSunday(geLastWeekSunday(date));//上上周周日
        Date lastMonday = geLastWeekMonday(date);//上周周一
        Date lastSunday = geLastWeekSunday(date);//上周周日
        Date thisMonday = getThisWeekMonday(date);//本周周一
        Date thisSunday = getThisWeekSunday(date);//本周周日
        Date nextMonday = getNextWeekMonday(date);//下周周一
        Date nowNextWeek = getNowNextOneWeek(date);//当前时间下周

        String nowLastOneWeek = getNowLastOneWeek(date);//当前时间上一周
        String nowLastTwoWeek = getNowLastTwoWeek(date);//当前时间上两周
        String nowLastThreeWeek = getNowLastThreeWeek(date);//当前时间上三周
        String nowLastFourWeek = getNowLastFourWeek(date);//当前时间上四周

        //遍历要预测的本周的时间点
        List<Date> thisWeekDates = getTimeSegment(thisMonday, nextMonday);

        System.out.println("开始时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

        Integer etcFlow = 0;
        Integer mtcFlow = 0;
        Integer flage = 0;

        for (String tollStationId : tollStationIdList) {
            ExpresswayInfEntity expresswayInfEntity = expresswayInfController.findExpresswayInfByTollStationId(tollStationId);
            for (int i = 0; i < thisWeekDates.size() - 1; i++) {
                Date thisWeekDate = thisWeekDates.get(i);
                String thisWeekDateLastOneWeek = getNowLastOneWeek(thisWeekDate);//当前时间上一周
                String thisWeekDateLastTwoWeek = getNowLastTwoWeek(thisWeekDate);//当前时间上两周
                String thisWeekDateLastThreeWeek = getNowLastThreeWeek(thisWeekDate);//当前时间上三周
                String thisWeekDateLastFourWeek = getNowLastFourWeek(thisWeekDate);//当前时间上四周

                //Flage，出入口标记，1--出口；2--入口
                List<FlowTrafficEntity> flowTrafficEntities1 = flowTrafficController.
                        findBystartTimeAndTollStationIdAndFlage1(thisWeekDateLastOneWeek, thisWeekDateLastTwoWeek, thisWeekDateLastThreeWeek, thisWeekDateLastFourWeek, tollStationId);
                TrHourFlowEntity trHourFlowEntity1 = avg(flowTrafficEntities1);

                trHourFlowEntity1.setStartTime(dtot(thisWeekDate));
                trHourFlowEntity1.setEndTime(dtot(addOneHour(thisWeekDate)));
                trHourFlowEntity1.setStationId(expresswayInfEntity.getTollStationId());
                trHourFlowEntity1.setStationName(expresswayInfEntity.getStationName());
                trHourFlowEntity1.setInsertTime(dtot(new Date()));
                trHourFlowEntity1.setFlag(1);

                trHourFlowController.insertTrHourFlow(trHourFlowEntity1);

                List<FlowTrafficEntity> flowTrafficEntities2 = flowTrafficController.
                        findBystartTimeAndTollStationIdAndFlage2(thisWeekDateLastOneWeek, thisWeekDateLastTwoWeek, thisWeekDateLastThreeWeek, thisWeekDateLastFourWeek, tollStationId);
                TrHourFlowEntity trHourFlowEntity2 = avg(flowTrafficEntities2);
                trHourFlowEntity2.setStartTime(dtot(thisWeekDate));
                trHourFlowEntity2.setEndTime(dtot(addOneHour(thisWeekDate)));
                trHourFlowEntity2.setStationId(expresswayInfEntity.getTollStationId());
                trHourFlowEntity2.setStationName(expresswayInfEntity.getStationName());
                trHourFlowEntity2.setInsertTime(dtot(new Date()));
                trHourFlowEntity2.setFlag(2);

                trHourFlowController.insertTrHourFlow(trHourFlowEntity2);
            }
        }
        System.out.println("结束时间：" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        System.out.println("流量数据已经同步到MySQL数据库");

    }

    //整点之后的半个小时对上个小时的整点进行改为真实数据
    @Scheduled(cron = "0 30 0/1 * * ? ")
//    @RequestMapping("/789")
    public void real() {
        //先去mysql的expresswayInf表中查询出天津所有的收费站(StationName)以及收费站编号(TollStationId)
        List<String> tollStationIdList = expresswayInfController.findTollStationIdNotNull();
        for (String tollStationIds : tollStationIdList) {
            ExpresswayInfEntity expresswayInfEntity = expresswayInfController.findExpresswayInfByTollStationId(tollStationIds);
            //STARTTIME
            String startTime = getLastHourTime(new Date(), 1);
            //TOLLSTATIONID
            String tollStationId = expresswayInfEntity.getTollStationId();
            //查询当前时间之前一个小时的真实数据，包括出入口
            List<FlowTrafficEntity> flowTrafficEntities = flowTrafficController.findBySTARTTIMEAndTOLLSTATIONID(startTime, tollStationId);
            if (flowTrafficEntities.size() > 0) {
                for (FlowTrafficEntity flowTrafficEntity : flowTrafficEntities) {
                    Integer etcFlow = flowTrafficEntity.getEtcFlow();
                    Integer mtcFlow = flowTrafficEntity.getMtcFlow();
                    Integer flage = flowTrafficEntity.getFlage();
                    //根据STARTTIME和STATIONID以及flage修改etcFlow和mtcFlow，并修改插入的时间
                    String insertTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
                    trHourFlowController.updateEtcFlowAndMtcFlowBySTARTTIMEAndSTATIONID(startTime, tollStationId, flage, etcFlow, mtcFlow, insertTime);
                    System.out.println("收费站：" + expresswayInfEntity.getStationName() + " 在 " + startTime + "的出入口的真实数据已经同步成功！");
                }
            } else {
                //暂时没有数据传输
            }
        }
    }

    //将Java date转化为 数据库Date
    public static java.sql.Timestamp dtot(java.util.Date d) {
        if (null == d)
            return null;
        return new java.sql.Timestamp(d.getTime());
    }

    //将数据库Date 转化为java date
    public static java.util.Date ttod(java.sql.Timestamp t) {
        if (null == t)
            return null;
        return new java.util.Date(t.getTime());
    }

    //求平均数
    public TrHourFlowEntity avg(List<FlowTrafficEntity> flowTrafficEntities) {
        Integer etcFlow = 0;
        Integer mtcFlow = 0;

        if (flowTrafficEntities.size() > 0) {
            for (FlowTrafficEntity flowTrafficEntity : flowTrafficEntities) {
                etcFlow += flowTrafficEntity.getEtcFlow();
                mtcFlow += flowTrafficEntity.getMtcFlow();
            }
            etcFlow = etcFlow / flowTrafficEntities.size();
            mtcFlow = mtcFlow / flowTrafficEntities.size();
        }

        TrHourFlowEntity trHourFlowEntity = new TrHourFlowEntity();

        trHourFlowEntity.setEtcFlow(etcFlow);
        trHourFlowEntity.setMtcFlow(mtcFlow);

        return trHourFlowEntity;
    }

    //将时间加一小时
    public static Date addOneHour(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR, 1);
        return cal.getTime();
    }

    //将时间减一小时
    public static Date removeOneHour(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR, -1);
        return cal.getTime();
    }

    //获取上周一
    public static Date geLastWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, -7);
        return cal.getTime();
    }

    //获取上周日
    public static Date geLastWeekSunday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    //获取本周周一
    public static Date getThisWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.getTime();
    }

    //获取本周周日
    public static Date getThisWeekSunday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, 6);
        return cal.getTime();
    }

    //获取下周周一
    public static Date getNextWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, 7);
        return cal.getTime();
    }

    //获取当前时间的上一周时间
    public static String getNowLastOneWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -7);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cal.getTime());
    }

    //获取当前时间的上两周时间
    public static String getNowLastTwoWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -14);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cal.getTime());
    }

    //获取当前时间的上三周时间
    public static String getNowLastThreeWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -21);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cal.getTime());
    }

    //获取当前时间的上四周时间
    public static String getNowLastFourWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -28);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cal.getTime());
    }

    //获取当前时间的下周时间
    public static Date getNowNextOneWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 7);
        return cal.getTime();
    }

    //获取某段时这里写代码片间内的所有日期
    public static List<Date> findDates(Date dBegin, Date dEnd) {
        List<Date> lDate = new ArrayList<Date>();
        lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            lDate.add(calBegin.getTime());
        }
        return lDate;
    }

    /**
     * 获取上n个小时整点小时时间
     *
     * @param date
     * @return
     */
    public static String getLastHourTime(Date date, int n) {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ca.set(Calendar.HOUR_OF_DAY, ca.get(Calendar.HOUR_OF_DAY) - n);
        date = ca.getTime();
        return sdf.format(date);
    }

    /**
     * 获取当前时间的整点小时时间
     *
     * @param date
     * @return
     */
    public static String getCurrHourTime(Date date) {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        date = ca.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    //获取指定一段时间内的整点时间戳
    public static List<Date> getTimeSegment(Date lastMonday, Date thisMonday) {

        String[] lastMondayNow1 = new SimpleDateFormat("yyyy-MM-dd").format(lastMonday).split("-");
        Integer.parseInt(lastMondayNow1[0]);            //获取年
        Integer.parseInt(lastMondayNow1[1]);            //获取月
        Integer.parseInt(lastMondayNow1[2]);            //获取日
        String[] lastMondayNow2 = new SimpleDateFormat("HH:mm:ss").format(lastMonday).split(":");
        Integer.parseInt(lastMondayNow2[0]);            //获取时（24小时制）
        Integer.parseInt(lastMondayNow2[1]);            //获取分
        Integer.parseInt(lastMondayNow2[2]);            //获取秒

        String[] thisMondayNow1 = new SimpleDateFormat("yyyy-MM-dd").format(thisMonday).split("-");
        Integer.parseInt(thisMondayNow1[0]);            //获取年
        Integer.parseInt(thisMondayNow1[1]);            //获取月
        Integer.parseInt(thisMondayNow1[2]);            //获取日
        String[] thisMondayNow2 = new SimpleDateFormat("HH:mm:ss").format(thisMonday).split(":");
        Integer.parseInt(thisMondayNow2[0]);            //获取时（24小时制）
        Integer.parseInt(thisMondayNow2[1]);            //获取分
        Integer.parseInt(thisMondayNow2[2]);            //获取秒

        Calendar cal = Calendar.getInstance();
        cal.set(Integer.parseInt(lastMondayNow1[0]), Integer.parseInt(lastMondayNow1[1]) - 1, Integer.parseInt(lastMondayNow1[2]), 0, 0, 0);
        cal.set(Calendar.MILLISECOND, 0);
        long startTime = cal.getTimeInMillis();
        cal.set(Integer.parseInt(thisMondayNow1[0]), Integer.parseInt(thisMondayNow1[1]) - 1, Integer.parseInt(thisMondayNow1[2]), 0, 0, 0);
        long endTime = cal.getTimeInMillis();
        final int seg = 60 * 60 * 1000;//每小时
        List<Date> result = new ArrayList<Date>((int) ((endTime - startTime) / seg + 1));
        for (long time = startTime; time <= endTime; time += seg) {
            result.add(new Date(time));
        }
        return result;
    }

}
